Monday's lecture note has lots of details (which all illustrate important concepts). Here is a high level summary, which still has lots of details. We discussed the relationship with two different kinds of objects: (1) Objects representing classes (2) Objects representing instance of classes (constructed from classes) For example, str refers to a class object; if x = str("a"), x refers to an object that is an instance of the class str (we might also call it a data object; we could write x = "a" but only because str is special/builtin class). The lecture focused on the namespaces of class and instance objects: how they are initialized, accessed, and updated (and how we can get explicit access to namespaces in these objects by using their underlying __dict__ of attribute). For instance objects, attributes are first looked-up in the instance object's namespace, and if not found there, are next looked-up in the class object's namespace: the class from which the instance object was constructed. We examined how if x.a is first looked-up in x's namespace, and then looked up in type(x)'s namespace. For methods, we discussed the Fundamental Equation of Object-Oriented Programming: x.m(...) is translated to type(x).m(x,...) if attribute m (here a non-static method) is not found in object x's namespace directly; for a static method it would translate to type(x).m(...) Class objects: a) Typically built in or defined by class C: ... The name C refers to the class object All names defined inside C are class attributes/names/variables/... b) Typically stores methods, but can store data (moderately often) c) Attribute a is accessed like C.a; when x = C(...) we can access C's attribute a by x.a (but only if x does not itself define attribute a) d) C.__dict__ is a dictionary storing C's namespace/attributes/variables Instance objects: a) Typically created from class: e.g., x = C(....) Where C's __init__ method is called with arguments ... to initialize the instance object's attributes/namespace (x refers to this object) b) Typically stores data (non-methods) but can store methods (rarely) c) Attribute a accessed like x.a d) x.__dict__ is a dictionary storing x's namespace/attributes Python is a Dynamic Language (unlike Java/C++): we can add/update/remove attributes from namespaces of class and instance objects while our code is running. Specifically we can (1) Put new (change old) attributes (e.g., methods) in a class object's namespace; now all its instance objects can get access to these attributes (can call these methods) (2) Put more attributes (data) into an instance object's namespace (even after __init__ is finished) Finally, there are 4 kinds of variables: (1) local variables (also parameters): these are names defined in functions (2) instance variables: these are attributes defined in instance objects (3) class variables: these are attributes defined in class objects. (3) global variables: these are are attributes defined in a module The most important rule about accessing a global variable in a function/method: A global variable can be accessed in a function/method if the function/method contains NO statements that attempt to rebind it. If a function/method ever attempts to rebind a variable, then it will be treated as a local variable, unless the function/method declares that name to be a global/nolocal variable. See the lecture notes for examples of all these different concepts.